﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ADDDF.Infrastructure
{
    public static class EntityHelper
    {
        /// <summary>
        /// Check whether both entities have equivalent keys. 
        /// </summary>
        public static bool HavingSameKeys(IEntity a, IEntity b)
        {
            // Do not allow null values
            if (a == null || b == null)
                throw new ArgumentNullException("Cannot compare keys when entity is null.");

            // True, if both are referencing the same object
            if (object.ReferenceEquals(a, b))
                return true;

            // Both entities have null keys, error
            if (a.Key == null && b.Key == null)
                throw new InvalidOperationException("Cannot determine the equality of two entities when they both have null key");

            // Use object.Equal to compare key equality.
            if (a.Key == null)
                return b.Key.Equals(a.Key);
            else
                return a.Key.Equals(b.Key);            
        }

        /// <summary>
        /// Check whether two entities are consider to be the same instance. The 
        /// default implementation compares their keys, and requires that their
        /// types must also be equivalent.
        /// </summary>
        public static bool AreSame(IEntity a, IEntity b)
        {
            if (!HavingSameKeys(a, b))
                return false;

            return a.GetType().Equals(b.GetType());
        }

        /// <summary>
        /// Creates and returns a new entity key that is unique among all entities
        /// , and all entity types. This can be used to generate a temporary key
        /// when using the two-step entity key assignment convention. The returned
        /// key satisfies the entity key requirements. See IEntityKey.
        /// </summary>
        public static object NewKey()
        {
            return Guid.NewGuid();
        }

        /// <summary>
        /// Help making a string variable never null (if null replace with empty).
        /// </summary>
        public static string NeverNull(string value)
        {
            if (value == null)
                return string.Empty;
            else
                return value;
        }

        /// <summary>
        /// Throws exception if an entity has null key.
        /// </summary>
        public static void ValidIfKeyedEntity(string parameterName, EntityBase value)
        {
            if (value == null)
                throw new InvalidValueException(parameterName, "entity cannot be null");

            if (value.Key == null)
                throw new InvalidValueException(parameterName, "Key of entity cannot be null");
        }

        public static void ValidIfNotTooLong(string parameterName, string value, int maxLength)
        {
            if (value == null)
                throw new InvalidValueException(parameterName, "cannot be null");

            if (value.Length > maxLength)
                throw new InvalidValueException(parameterName, "cannot have more than " + maxLength.ToString() + " characters");
        }

        public static void ValidIfNotNull(string parameterName, object value)
        {
            if (value == null)
                throw new InvalidValueException(parameterName, "cannot be null");
        }

        public static void ValidIfInRange(string parameterName, decimal min, decimal max, decimal value)
        {
            if (value < min || value > max)
                throw new InvalidValueException(parameterName, "must be in range " + min + " - " + max);
        }

        public static void ValidIfAtLeast(string parameterName, decimal min, decimal value)
        {
            if (value < min)
                throw new InvalidValueException(parameterName, "must be at least " + min);
        }

        public static void ValidIfDateOnly(string parameterName, DateTime value)
        {
            if (value.Hour != 0 || value.Minute != 0 || value.Second != 0 || value.Millisecond != 0)
                throw new InvalidValueException(parameterName, "cannot have Time component");
        }
    }
}
